#include "sve_network.h"


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Servidor TCP
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

sve_network::sve_network(QWidget *parent):QTcpServer(){
    tcpServer = new QTcpServer(parent);
    delay_server=10000;

    // Crea la base de datos que contiene los ID de los nodos que se les permitirá conectarse al servidor
    if(!QFile::exists("nodos.db")){
        QString cmd("sqlite3 ");
        cmd.append("nodos.db ");
        cmd.append("'create table nodos(IP BLOB, ID BLOB);'");
        system(cmd.toAscii().data());
    }

    if(!QSqlDatabase::contains("IDconex"))
        QSqlDatabase::addDatabase("QSQLITE","IDconex");
}

sve_network::~sve_network(){}

QStringList sve_network::show_interfaces(){
    QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
    QStringList str_interfaces;
    for(int i=0;i<interfaces.size();i++){
        if(interfaces.at(i).name()!="lo")
            str_interfaces << interfaces.at(i).name();
    }
    return str_interfaces;
}

QStringList sve_network::interface_info(QString interface_name){
    QStringList buffer;
    QNetworkInterface interface(QNetworkInterface::interfaceFromName(interface_name));
    if(!interface.addressEntries().isEmpty()){
        buffer << interface.addressEntries().at(0).ip().toString();
        buffer << interface.addressEntries().at(0).netmask().toString();}
    return buffer;
}

bool sve_network::open_server(){
    QSettings settings("AIR", "SVE");
    settings.beginGroup("Network");
    if(settings.contains("IP") && settings.contains("Port")){

        QHostAddress myIP = QHostAddress(settings.value("IP").toString());

        if (!tcpServer->listen(myIP,settings.value("Port").toInt())){
            settings.endGroup();
            return false;
        }
        settings.endGroup();
    }
    else{
        show_msg("No se ha configurado el servidor!",
                 "Dirijase a la a seccion de configuracion y seleccione "
                 "la interfaz y el puerto en que desea habilitar el servidor","",QMessageBox::Critical);
        return false;
    }
    return true;
}

void sve_network::close_server(){
    tcpServer->close();
}

void sve_network::send_msg(QString msg, QTcpSocket &client){
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);

    out << (quint16)0;
    out << msg;
    out.device()->seek(0);
    out << (quint16)(block.size() - sizeof(quint16));

    if(!client.isWritable()){
        return;
    }

    int bytes =client.write(block);
}

bool sve_network::read_msg(QString &msg,QTcpSocket &client){
    while (client.bytesAvailable() < (int)sizeof(quint16)) {
        if (!client.waitForReadyRead(delay_server)) {
            return false;
        }
    }

    blockSize = 0;

    QDataStream in(&client);
    in.setVersion(QDataStream::Qt_4_0);
    in >> blockSize;

    while (client.bytesAvailable() < blockSize) {
        if (!client.waitForReadyRead(delay_server)) {
            return false;
        }
    }

    in >> msg;
    in.~QDataStream();
    return true;
}

bool sve_network::voting_Connection(){

    clientConnection = new QTcpSocket();
    clientConnection = tcpServer->nextPendingConnection();
    //connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()),Qt::UniqueConnection);

    if(!chk_Client()){
        QMessageBox::critical(0,"temporal","cliente no valido");
        return false;
    }

    // Lee indicacion de qué tipo de conexion se requiere: solicitud de boleta de votacion, o envio del voto
    if (!read_msg(msg_RX,*clientConnection)){
        return false;}

    switch(msg_RX.toInt()){
        case sve_network::M1msg:
            emit M1_signal();
            break;
        case sve_network::M6msg:
            emit M6_signal();
            break;
    }


    return true;
}

void sve_network::config_Connection(){
    clientConnection = new QTcpSocket();
    clientConnection = tcpServer->nextPendingConnection();
    if(!read_msg(msg_RX,*clientConnection)){
        show_msg("No se ha recibido ningun mensaje del nodo!","","",QMessageBox::Critical);
        return;
    }
    emit config_signal();
}

bool sve_network::chk_Client(){
    // Lee y verifica el ID del nodo de votacion
    if (!read_msg(msg_RX,*clientConnection)){
        return false;}
// Crea la conexion
    QSqlDatabase IDdb = QSqlDatabase::database("IDconex",false);
    IDdb.setDatabaseName("nodos.db");
    IDdb.open();

// Crea el modelo
    QSqlTableModel IDmodel(0,IDdb);
    IDmodel.setTable("nodos");
    IDmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    IDmodel.setFilter(QString("ID='").append(msg_RX).append("'"));
    IDmodel.select();

    if(IDmodel.rowCount()==0){
        return false;
    }

    // Envia una señal de disponibilidad
    msg_TX=QString::number(sve_network::hearing);
    send_msg(msg_TX,*clientConnection);
    return true;
}

bool sve_network::chk_IP(QString IP){
// Crea la conexion
    QSqlDatabase IDdb = QSqlDatabase::database("IDconex",false);
    IDdb.setDatabaseName("nodos.db");
    IDdb.open();

// Crea el modelo
    QSqlTableModel IDmodel(0,IDdb);
    IDmodel.setTable("nodos");
    IDmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    IDmodel.setFilter(QString("IP='").append(IP).append("'"));
    IDmodel.select();

    if(IDmodel.rowCount()==0){
        return false;
    }
    return true;
}

QString sve_network::shift_String(QString &msg){
    QString buffer;

    int shift = msg.indexOf("&&");

    for(int j=0;j<shift; j++){
        buffer.append(msg.at(j));
    }

    msg.remove(0,shift);
    msg.remove(0,2); // borra &&
    return buffer;
}

int sve_network::show_msg(QString message, QString info, QString detail, QMessageBox::Icon icono, QMessageBox::StandardButtons buttons){
    QMessageBox message1(0);
    message1.setStyleSheet("QAbstractButton{background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(157, 246, 227, 255), stop:1 rgba(168, 168, 168, 255)); border-top-color: rgb(233, 248, 241); border-left-color: rgb(233, 248, 241); border-bottom-color: rgb(81, 120, 107); border-right-color: rgb(81, 120, 107); border-style: outset; border-width: 2px; padding: 3px; border-radius: 15px; min-height:20 px; min-width:80 px; color: black} QAbstractButton:pressed{background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(97, 186, 167, 255), stop:1 rgba(148, 148, 148, 255)); color: rgb(85, 0, 0); border-style: inset; border-top-color: rgb(81, 120, 107); border-left-color: rgb(81, 120, 107); border-bottom-color: rgb(233, 248, 241); border-right-color: rgb(233, 248, 241);} QLabel{color: rgb(255,255,100); background-color: rgba(170, 255, 255, 0)} QDialog{background-color: rgb(132, 150, 255);}");
    message1.setWindowModality(Qt::ApplicationModal);
    message1.setText(message.prepend("<b>").append("</b>"));
    message1.setInformativeText(info);
    message1.setDetailedText(detail);
    message1.setIcon(icono);
    message1.setStandardButtons(buttons);
    return message1.exec();
}

void sve_network::reg_nodo(QString IP, QString ID){
// Crea la conexion
    QSqlDatabase IDdb = QSqlDatabase::database("IDconex",false);
    IDdb.setDatabaseName("nodos.db");
    IDdb.open();

// Crea el modelo
    QSqlTableModel IDmodel(0,IDdb);
    IDmodel.setTable("nodos");
    IDmodel.setEditStrategy(QSqlTableModel::OnManualSubmit);
    IDmodel.setFilter(QString("IP='").append(IP).append("'"));
    IDmodel.select();

    if(IDmodel.rowCount()==0){
        IDmodel.insertRows(0, 1);
        IDmodel.setData(IDmodel.index(0, IDmodel.fieldIndex("IP")),IP);
    }
    IDmodel.setData(IDmodel.index(0, IDmodel.fieldIndex("ID")),ID);
    IDmodel.submitAll();
    return;
}



